﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using MyBatisCreate.Entity;
using System.IO;
using System.Collections;

namespace MyBatisCreate
{
    public partial class Form1 : Form
    {
        string conStr;
        SqlConnection con;
        string str = System.Environment.CurrentDirectory;

        public Form1()
        {

            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            try
            {
                if (host.Text.Trim().Length == 0)
                {
                    throw new Exception("请输入主机名！");
                }
                if (database.Text.Trim().Length == 0)
                {
                    throw new Exception("请输入数据库！");
                }
                if (username.Text.Trim().Length == 0)
                {
                    throw new Exception("请输入用户名！");
                }
                conStr = String.Format("Data Source={0};Initial Catalog={1};User Id={2};Password={3};", host.Text, database.Text, username.Text, password.Text);
                con = new SqlConnection(conStr);
                createButton.Enabled = false;
                tableInfo.Enabled = false;
            
                con.Open();
                string sql = "SELECT 0 checked ,name tablename FROM sysobjects WHERE xtype='U' order by name";
                SqlDataAdapter sda = new SqlDataAdapter(sql, con);
                DataTable dt = new DataTable();
                sda.Fill(dt);
                List<TableInfo> list = new List<TableInfo>();
                DataRowCollection rows = dt.Rows;
                TableInfo ti;
                foreach (DataRow dr in rows)
                {
                    ti = new TableInfo();
                    ti.tableName = dr.ItemArray[1].ToString();
                    ti.entityName = converName(dr.ItemArray[1].ToString());
                    list.Add(ti);
                }
                tableInfo.DataSource = list;
                tableInfo.Enabled = true;
                createButton.Enabled = true;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            
        }
        private string converName(string value)
        {
            char[] sp = {'_'};
            string[] vals=value.Split(sp);
            StringBuilder sb = new StringBuilder();
            foreach (string s in vals)
            {
                sb.Append(s.Substring(0,1).ToUpper());
                sb.Append(s.Substring(1).ToLower());
            }
            return sb.ToString();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                bool flag = true;
                foreach (DataGridViewRow dgvr in tableInfo.Rows)
                {
                    DataGridViewCell cell = dgvr.Cells[0];
                    if (Boolean.Parse(cell.Value.ToString()))
                    {
                        flag = false; ;
                        craeteEntityClassAndMapperXml(dgvr.Cells[1].Value.ToString(), dgvr.Cells[2].Value.ToString());
                    }
                }
                if (flag)
                {
                    MessageBox.Show("请至少选择一行记录！");
                }
                else {
                    MessageBox.Show("恭喜你生成成功！");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            
        }
        /**
         * 创建映射文件
         * 
         */
        private void craeteEntityClassAndMapperXml(string tableName,string entityName)
        {
            string sql = "SELECT a.name AS columnname, CASE WHEN EXISTS ( SELECT 1 FROM dbo.sysindexes si INNER JOIN dbo.sysindexkeys sik ON si.id = sik.id AND si.indid = sik.indid INNER JOIN dbo.syscolumns sc ON sc.id = sik.id AND sc.colid = sik.colid INNER JOIN dbo.sysobjects so ON so.name = so.name AND so.xtype = 'PK' WHERE sc.id = a.id AND sc.colid = a.colid ) THEN '1' ELSE '0' END AS pk, b.name AS type, a.length AS length, ISNULL( COLUMNPROPERTY(a.id, a.name, 'Scale'), 0 ) AS flength FROM dbo.syscolumns AS a LEFT OUTER JOIN dbo.systypes AS b ON a.xtype = b.xusertype INNER JOIN dbo.sysobjects AS d ON a.id = d.id AND d.xtype = 'U' AND d.status >= 0 LEFT OUTER JOIN dbo.syscomments AS e ON a.cdefault = e.id LEFT OUTER JOIN sys.extended_properties AS g ON a.id = g.major_id AND a.colid = g.minor_id LEFT OUTER JOIN sys.extended_properties AS f ON d.id = f.major_id AND f.minor_id = 0 WHERE d.name = '{0}' order by pk desc";
            SqlDataAdapter sda = new SqlDataAdapter(String.Format(sql,tableName), con);
            DataTable dt = new DataTable();
            sda.Fill(dt);
            DataRowCollection rows = dt.Rows;
            int pkCount=0;
            foreach (DataRow dr in rows)
            {
                pkCount += Convert.ToInt32(dr.ItemArray[1].ToString());
            }
            if (pkCount > 1)
            {
                CreateEntityPKFile(rows, entityName);
            }
            CreateEntityFile(rows, entityName, pkCount > 1);
            CreateMapperFile(rows, entityName, tableName, pkCount);


            CreateMapper(entityName, rows, pkCount > 1);
        }

        private void CreateMapper(string entityName, DataRowCollection rows, bool com)
        {
            FileStream fs = new FileStream("Mapper.tpl", FileMode.Open);
            StreamReader sr = new StreamReader(fs);

            string temp = sr.ReadToEnd();
            sr.Close();
            fs.Close();
            string a = temp.ToString();
            a = a.Replace("${EntityClass}", entityName);
            a = a.Replace("${namespace}", namespaceStr.Text);
            string keyClass = "";
            if (com)
            {
                keyClass = entityName + "Key";
            }
            else
            {
                keyClass = typeConver(rows[0]);
            }
            a = a.Replace("${KeyClass}", keyClass);
            string dir = str + "\\Mapper\\";
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            fs = new FileStream(dir + "\\" + entityName + "Mapper.cs", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            sw.Write(a);
            sw.Close();
            fs.Close();
        }
        /**
         * 生成Mapper文件
         * 
         */
        public void CreateMapperFile(DataRowCollection rows, string entityName,string tableName,int com)
        {
            string dir = str+"\\sqlMap\\";
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            FileStream fs = new FileStream(dir + "\\" + entityName + "Mapper.xml", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            sw.Write("<sqlMap namespace=\"");
            sw.Write(namespaceStr.Text+"."+entityName);
            sw.WriteLine("\" xmlns=\"http://ibatis.apache.org/mapping\"");
            sw.WriteLine("\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">");
            BuildResultMaps(rows, entityName, sw);

            sw.WriteLine("\t<statements>");
            BuildSelectByPrimaryKey(rows, entityName, tableName, com, sw);

            BuildInsert(rows, entityName, tableName, sw);
            BuildUpdate(rows, entityName, tableName, com, sw);

            BuildDelete(rows, entityName, tableName, com, sw);

            sw.WriteLine("\t</statements>");
            sw.WriteLine("</sqlMap>");
            sw.Close();
            fs.Close();
        }
        /**
         * 生成根据主键删除语句
         * 
         */
        private void BuildDelete(DataRowCollection rows, string entityName, string tableName, int com, StreamWriter sw)
        {
            sw.Write("\t\t<delete id=\"delete\" parameterClass=\"");
            CreateKeyClass(rows, entityName, com, sw);

            sw.Write("\t\t\tdelete from ");
            sw.WriteLine(tableName);
            sw.WriteLine("\t\t\twhere");
            sw.Write("\t\t\t\t");
            CreatePrimaryWhereSql(rows, com, sw);
            sw.WriteLine("\t\t</delete>");
        }
        /**
         * 生成根据主键更新语句
         * 
         */
        private void BuildUpdate(DataRowCollection rows, string entityName, string tableName, int com, StreamWriter sw)
        {
            sw.Write("\t\t<update id=\"update\" parameterClass=\"");

            sw.Write(namespaceStr.Text);
            sw.Write(".");
            sw.Write(entityName);
            sw.WriteLine("\">");

            sw.Write("\t\t\tupdate ");
            sw.WriteLine(tableName);
            sw.WriteLine("\t\t\tset ");
            StringBuilder where = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                if (dr.ItemArray[1].ToString().Equals("0"))
                {
                    sw.Write("\t\t\t\t");
                    sw.Write(dr.ItemArray[0]);
                    sw.Write(" = ");
                    sw.Write("#");
                    sw.Write(converName(dr.ItemArray[0].ToString()));
                    sw.WriteLine("#");
                    sw.Flush();
                }
            }

            sw.WriteLine("\t\t\twhere");
            sw.Write("\t\t\t\t");
            CreatePrimaryWhereSql(rows, com, sw);
            sw.WriteLine("\t\t</update>");
        }

        private void CreateKeyClass(DataRowCollection rows, string entityName, int com, StreamWriter sw)
        {
            if (com > 1)
            {
                sw.Write(namespaceStr.Text);
                sw.Write(".");
                sw.Write(entityName);
                sw.WriteLine("Key\">");
            }
            else
            {
                foreach (DataRow dr in rows)
                {
                    if (dr.ItemArray[1].ToString().Equals("1"))
                    {
                        sw.Write(typeConver(dr));
                        sw.WriteLine("\">");
                        break;
                    }
                }
            }
        }
        /**
        * 
        * 生成插入语句
        * 
        * 
        **/
        private void BuildInsert(DataRowCollection rows, string entityName, string tableName, StreamWriter sw)
        {
            sw.Write("\t\t<insert id=\"insert\" parameterClass=\"");
            sw.Write(namespaceStr.Text);
            sw.Write(".");
            sw.Write(entityName);
            sw.WriteLine("\">");

            sw.Write("\t\t\tinsert into");
            sw.WriteLine(tableName);
            sw.Write("\t\t\t\t(");

            StringBuilder sb = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                sb.Append(dr.ItemArray[0]);
                sb.Append(" ,");
            }
            sb.Remove(sb.Length - 1, 1);
            sw.Write(sb.ToString());
            sw.WriteLine(")");
            sw.WriteLine("\t\t\tvalues");
            sw.Write("\t\t\t\t(");

            sb = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                sb.Append(" #");
                sb.Append(converName(dr.ItemArray[0].ToString()));
                sb.Append("#,");
            }
            sb.Remove(sb.Length - 1, 1);
            sw.Write(sb.ToString());
            sw.WriteLine(")");
            sw.WriteLine("\t\t<insert>");
        }

        /**
        * 
        * 生成根据主键查询的语句
        * 
        * 
        **/
        private void BuildSelectByPrimaryKey(DataRowCollection rows, string entityName, string tableName, int com, StreamWriter sw)
        {
            sw.Write("\t\t<select id=\"selectByPrimaryKey\" resultMap=\"");
            sw.Write(entityName);

            sw.Write("Result\" parameterClass=\"");
            CreateKeyClass(rows, entityName, com, sw);

            sw.WriteLine("\t\t\tselect ");
            StringBuilder sb = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                sb.Append(dr.ItemArray[0]);
                sb.Append(" , ");
            }
            sb.Remove(sb.Length - 2, 2);
            sw.Write("\t\t\t\t");
            sw.WriteLine(sb.ToString());
            sw.Write("\t\t\tfrom ");
            sw.WriteLine(tableName);
            sw.WriteLine("\t\t\twhere ");
            sw.Write("\t\t\t\t");
            CreatePrimaryWhereSql(rows, com, sw);

            sw.WriteLine("\t\t</select>");
        }
       /**
        * 
        * 生成根据主键查询时的条件语句
        * 
        * 
        **/
        private void CreatePrimaryWhereSql(DataRowCollection rows, int com, StreamWriter sw)
        {
            if (com > 1)
            {
                int i = 1;
                foreach (DataRow dr in rows)
                {
                    if (dr.ItemArray[1].ToString().Equals("1"))
                    {
                        sw.Write(dr.ItemArray[0]);
                        sw.Write(" = #");
                        sw.Write(converName(dr.ItemArray[0].ToString()));
                        sw.Write("#");
                        if (i < com)
                        {
                            sw.Write(" and ");
                        }
                        else
                        {
                            sw.WriteLine("");
                            break;
                        }
                    }
                    i++;
                }
            }
            else
            {
                foreach (DataRow dr in rows)
                {
                    sw.Write(dr.ItemArray[0]);
                    sw.WriteLine(" = #value# ");
                    break;
                }
            }
        }
        /**
         * 
         * 生成实体对应的基本映射关系
         * 
         * 
         **/
        private void BuildResultMaps(DataRowCollection rows, string entityName, StreamWriter sw)
        {
            sw.WriteLine("\t<resultMaps>");
            sw.Write("\t\t<resultMap id=\"");
            sw.Write(entityName);
            sw.Write("Result\" class=\"");
            sw.Write(namespaceStr.Text + "." + entityName);
            sw.WriteLine("\">");
            StringBuilder fields = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                //<result property="DeviceId" column="Device_Id" dbType="varchar" type="string" />
                fields.Append("\t\t\t<result property=\"");
                fields.Append(converName(dr.ItemArray[0].ToString()));
                fields.Append("\" column=\"");
                fields.Append(dr.ItemArray[0].ToString());
                fields.Append("\" dbType=\"");
                fields.Append(dr.ItemArray[2].ToString());
                fields.Append("\" type=\"");
                fields.Append(typeConver(dr));
                fields.AppendLine("\" />");
            }
            sw.Write(fields.ToString());
            sw.WriteLine("\t\t</resultMap>");
            sw.WriteLine("\t</resultMaps>");
        }
        /**
         * 
         * 生成实体类主键文件
         * 
         * 
         **/
        private void CreateEntityPKFile(DataRowCollection rows, string entityName)
        {
            string dir = str+"\\Models";
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            FileStream fs = new FileStream(dir + "\\" + entityName + "Key.cs", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine("using System;");
            sw.WriteLine("");
            sw.Write("namespace ");
            sw.Write(namespaceStr.Text);
            sw.Write(".");
            sw.WriteLine("Models");
            sw.WriteLine("{");
            sw.Write("\tpublic class ");
            sw.Write(entityName);
            sw.WriteLine("Key");
            sw.WriteLine("{");
            StringBuilder fields = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                if (dr.ItemArray[1].ToString().Equals("1"))
                {
                    BuildField(fields, dr);
                }
            }
            sw.Write(fields.ToString());
            sw.WriteLine("\t}");
            sw.WriteLine("}");
            sw.Close();
            fs.Close();
        }
        /**
         * 
         * 生成实体类文件
         * 
         * 
         **/
        private void CreateEntityFile(DataRowCollection rows, string entityName, bool com)
        {
            string dir = str + "\\Models";
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            FileStream fs = new FileStream(dir + "\\" + entityName + ".cs", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine("using System;");
            sw.WriteLine("");
            sw.Write("namespace ");
            sw.Write(namespaceStr.Text);
            sw.Write(".");
            sw.WriteLine("Models");
            sw.WriteLine("{");
            sw.Write("\tpublic class ");
            sw.Write(entityName);
            if (com)
            {
                sw.Write(" : ");
                sw.Write(entityName);
                sw.Write("Key");
            }
            sw.WriteLine("{");
            StringBuilder fields = new StringBuilder();
            foreach (DataRow dr in rows)
            {
                if (com && dr.ItemArray[1].ToString().Equals("0"))
                {
                    BuildField(fields, dr);
                }
                else
                {
                    BuildField(fields, dr);
                }
            }
            sw.Write(fields.ToString());
            sw.WriteLine("\t}");
            sw.WriteLine("}");
            sw.Close();
            fs.Close();
        }
        /**
         *
         * 生成字段对应的属性及对应属性的set，get方法
         * 
         **/
        private void BuildField(StringBuilder fields, DataRow dr)
        {
            fields.Append("\t\tpublic ");
            fields.Append(typeConver(dr));
            fields.Append(" ");
            fields.Append(converName(dr.ItemArray[0].ToString()));
            fields.AppendLine(" { set; get; }");
        }
        /**
         *
         * 数据库与C#类型转化
         * 
         **/
        private string typeConver(DataRow dr)
        {
            string dbType = dr.ItemArray[2].ToString();
            dbType = dbType.Trim().ToLower();
            if (dbType.Equals("varchar") || dbType.Equals("char"))
            {
                return "string";
            }
            else if (dbType.Equals("date"))
            {
                return "DateTime";
            }
            else if (dbType.Equals("decimal"))
            {
                int flength = Convert.ToInt32(dr.ItemArray[4].ToString());
                if (flength > 0)
                {
                    return "double";
                }
                else 
                {
                    int length = Convert.ToInt32(dr.ItemArray[3].ToString());
                    return "long";
                }
                
            }
            System.Console.WriteLine(dbType);
            return "";
        }
    }
}
